perf(auth): optimize getSession with in-memory fast-path and lockless… - #2618
perf(auth): optimize getSession with in-memory fast-path and lockless…#2618karan-963 wants to merge 1 commit into
Conversation
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hey team! Just following up on this PR with additional testing and de-risking context. Since this addresses the long-standing mount contention discussed in #970, I wanted to loop in @Ruthenz @MatthewDlr @lauri865 and @Vickyfreshmusik to verify if this resolves their original reproduction cases. 🛡️ Edge Cases & Stress Scenarios Verified:Alongside the 144 passing unit tests and the live benchmark harness, I’ve verified the following runtime scenarios:
🌐 Live Interactive Benchmark: Anyone can test and benchmark the speedup directly in their browser: Are there any additional runtime environments (or specific mobile/SSR adapters) the core team would like me to add test coverage for to help with the review? |
perf(auth): optimize getSession with in-memory fast-path and lockless reads
🔍 Description
This PR resolves the performance degradation in
supabase.auth.getSession()during initial component mounting and page rendering phases.What changed?
this._acquireLock) aroundgetSession(). Read-only session lookups are idempotent and safe to execute concurrently without queuing behind mutual exclusion locks. Mutating operations (refreshSession,setSession,signOut) remain strictly guarded._inFlightLoadSession): Deduplicated concurrent initial calls to__loadSession(). When multiple components mount simultaneously, all callers share a single in-flight Promise, guaranteeing only 1 underlying storage read instead of_inMemorySession): Cached valid, unexpired sessions in memory. Synchronized the cache with_saveSession,_removeSession,_notifyAllSubscribers, and token refreshes. Subsequent calls resolve in <0.001 ms (sub-microsecond).deepClone): Returned sessions on the fast-path pass throughdeepClone(this._inMemorySession)to guarantee that user application code mutating properties onsessionorusercannot corrupt the SDK's internal cache.Why was this change needed?
When multiple components mount simultaneously during page rendering or hydration (e.g. in React / Next.js), calling
supabase.auth.getSession()in parallel resulted in severe serialization latency (20ms to 450ms+ depending on storage and lock contention). Under async storage adapters (Next.js SSR cookies, React Native AsyncStorage) and custom locks (processLock,navigator.locks), each component waited in line for previous locks to release.Closes #970
📸 Screenshots/Examples
1. In-Browser Live Benchmark Comparison (100 Concurrent Component Mounts)
(Tested live in browser engine with high-resolution timers
performance.now(). Timings use~to reflect typical runtime variability across browser turns and hardware):~117 ms – ~452 ms~0.70 ms – ~2.8 ms~0.35 ms~61 ms – ~218 ms~0.58 ms – ~1.2 ms~0.003 ms~84 ms – ~350 ms~0.40 ms – ~0.9 ms~0.10 msgetSession()~1.6 ms~0.0008 ms~0.003 ms2. Live Interactive Test Harness
🌐 Live Demo (GitHub Pages): https://karan-963.github.io/supabase-js/
Side-by-Side 100-Component Mount & Real SDK Output:
🔄 Breaking changes
📋 Checklist
<type>(<scope>): <description>pnpm nx formatto ensure consistent code formatting📝 Additional notes
Security & Edge Cases Considered:
this._inMemorySessiondirectly could allow callers to mutate properties ondata.session.user. We hardened the fast-path to returndeepClone(this._inMemorySession).localStorage.clear()): CallinglocalStorage.clear()externally leaves_inMemorySessionuntil page reload or token expiry, consistent with standard token caching (Firebase Auth, Auth0)._removeSession()andsignOut()remain the canonical eviction path.deepCloneisolation:PASS~0.40ms):PASSPASS~9.80ms):PASSBroadcastChannelevent dispatch:PASSpnpm exec nx test:unit supabase-js).